﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace Heimdallr
{
    /// <summary>
    /// Provides data for events that prepresent failed operation.
    /// </summary>
    public class ExceptionsEventArgs : EventArgs
    {
        #region Field

        private readonly ReadOnlyCollection<Exception> errors;
        private readonly object userState;

        #endregion

        #region Property

        /// <summary>
        /// Gets a collection of error information.
        /// </summary>
        public ReadOnlyCollection<Exception> Errors
        {
            get { return this.errors; }
        }

        /// <summary>
        /// Gets a value that represents the user state.
        /// </summary>
        public object UserState
        {
            get { return this.userState; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class, using specified single error information.
        /// </summary>
        /// <param name="error">A specified error information.</param>
        /// <exception cref="ArgumentNullException">Parameter <paramref name="error"/> is null.</exception>
        public ExceptionsEventArgs(Exception error)
            : this(CheckArgument(error), null)
        {
        }

        /// <summary>
        /// Initializes a new instance of this class, using specified single error information and user state.
        /// </summary>
        /// <param name="error">A specified error information.</param>
        /// <param name="userState">A specified user state.</param>
        /// <exception cref="ArgumentNullException">Parameter <paramref name="error"/> is null.</exception>
        public ExceptionsEventArgs(Exception error, object userState)
            : this(CheckArgument(error), userState)
        {
        }

        /// <summary>
        /// Initializes a new instance of this class, using specified errors.
        /// </summary>
        /// <param name="errors">Specified errors.</param>
        /// <exception cref="ArgumentNullException">Parameter <paramref name="errors"/> is null.</exception>
        /// <exception cref="ArgumentException">Parameter <paramref name="errors"/> is an empty collection.</exception>
        public ExceptionsEventArgs(IEnumerable<Exception> errors)
            : this(errors, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of this class, using specified errors and user state.
        /// </summary>
        /// <param name="errors">Specified errors.</param>
        /// <param name="userState">A specified user state.</param>
        /// <exception cref="ArgumentNullException">Parameter <paramref name="errors"/> is null.</exception>
        /// <exception cref="ArgumentException">Parameter <paramref name="errors"/> is an empty collection.</exception>
        public ExceptionsEventArgs(IEnumerable<Exception> errors, object userState)
        {
            if (errors == null)
                throw new ArgumentNullException("errors");

            if (!errors.Any())
                throw new ArgumentException("Collection is empty.", "errors");

            this.errors = new ReadOnlyCollection<Exception>(errors.ToArray());
            this.userState = userState;
        }

        #endregion

        #region Override

        /// <summary>
        /// Returns a string that represents the error informations.
        /// </summary>
        /// <returns>A string that represents the error informations.</returns>
        public override string ToString()
        {
            return string.Join(Environment.NewLine, this.errors);
        }

        #endregion

        #region Other

        private static Exception[] CheckArgument(Exception error)
        {
            if (error == null)
                throw new ArgumentNullException("error");

            return new[] { error };
        }

        #endregion
    }
}